package com.dx.financehy.config;

import org.slf4j.MDC;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskDecorator;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * description:创建线程工具类
 * <p>
 * 线程池工作流程
 * 1、线程在有任务的时候会创建核心的线程数corePoolSize
 * 2、当线程满了（有任务但是线程被使用完）不会立即扩容,而是放到阻塞队列中,当阻塞队列满了之后才会继续创建线程。
 * 3、如果队列满了,线程数达到最大线程数则会执行拒绝策略。
 * 4、当线程数大于核心线程数事,超过KeepAliveTime(闲置时间),线程会被回收,最终会保持corePoolSize个线程。
 * <p>
 * 线程池状态
 * RUNNING : 在RUNNING状态下，线程池可以接收新的任务和执行已添加的任务。
 * SHUTDOWN : 线程池处在SHUTDOWN状态时，不接收新任务，但能处理已添加的任务。
 * STOP : 线程池处在STOP状态时，不接收新任务，不处理已添加的任务，并且会中断正在执行的任务。
 * TIDYING : 当所有的任务已终止，记录的”任务数量”为0，线程池会变为TIDYING状态。当线程池变为TIDYING状态时，会执行钩子函数terminated()。
 * TERMINATED : 当钩子函数terminated()被执行完成之后，线程池彻底终止，就变成TERMINATED状态。
 */
@EnableAsync
@Configuration
public class ThreadPoolConfig {
    /**
     * 核心线程数（默认线程数）
     * CPU密集型：corePoolSize = CPU核数 + 1
     * IO密集型：corePoolSize = CPU核数 * 2
     */
    private static final int CORE_POOL_SIZE = 30;

    /**
     * 最大线程数
     */
    private static final int MAX_POOL_SIZE = 900;

    /**
     * 允许线程空闲时间（单位：默认为秒）
     */
    private static final int KEEP_ALIVE_TIME = 10;

    /**
     * 缓冲队列大小
     */
    private static final int QUEUE_CAPACITY = 100;

    /**
     * 线程池名前缀
     */
    private static final String THREAD_NAME_PREFIX = "async-pool-";

    /**
     * 当使用@Async注解时，需指定使用此线程池
     *
     * @return 线程池实例
     */
    @Bean(value = "threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor asyncTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(CORE_POOL_SIZE);
        executor.setMaxPoolSize(MAX_POOL_SIZE);
        executor.setQueueCapacity(QUEUE_CAPACITY);
        executor.setKeepAliveSeconds(KEEP_ALIVE_TIME);
        executor.setThreadNamePrefix(THREAD_NAME_PREFIX);
        // 线程池对拒绝任务的处理策略,拒绝执行且抛出异常
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
        //未有任务时关闭核心线程池
        executor.setAllowCoreThreadTimeOut(true);
        //定义装饰器
        executor.setTaskDecorator(new MdcTaskDecorator());
        // 初始化
        executor.initialize();
        return executor;
    }

    class MdcTaskDecorator implements TaskDecorator {
        @Override
        public Runnable decorate(Runnable runnable) {
            Map<String, String> contextMap = MDC.getCopyOfContextMap();
            return () -> {
                try {
                    if (contextMap != null) {
                        MDC.setContextMap(contextMap);
                    }
                    runnable.run();
                } finally {
                    //MDC.clear();
                }
            };
        }
    }
}
